Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix integer overflow in ecmult_multi_var when n is large #568

Merged
merged 1 commit into from
Feb 25, 2019

Conversation

jonasnick
Copy link
Contributor

Without this PR ecmult_multi could return wrong results. If the number of points n is large enough then some or all multiplications could be skipped or the function could end up in an infinite loop. This PR adds two checks to prevent n from wrapping around.

if (n > (size_t)-1 - (max_points-1)) {
return 0;
}
*n_batches = (n + max_points-1) / max_points;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*n_batches = (n + max_points-1) / max_points;
*n_batches = (n + (max_points-1)) / max_points;

you could also CHECK/VERIFY that *n_batches != 0 here. As I understand it, this can only happen if n == 0 and then this function won't be called currently.

if (n > (size_t)-1 - (*n_batches-1)) {
return 0;
}
*n_batch_points = (n + *n_batches-1) / *n_batches;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*n_batch_points = (n + *n_batches-1) / *n_batches;
*n_batch_points = (n + (*n_batches-1)) / *n_batches;

@apoelstra
Copy link
Contributor

ACK

@jonasnick
Copy link
Contributor Author

jonasnick commented Oct 24, 2018

@real-or-random I added a commit

static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_points, size_t n) {
if (max_points == 0) {
return 0;
} else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, thanks

@real-or-random
Copy link
Contributor

Oh I didn't want to bother you with nits only. I assumed that the missing parentheses are real bugs but no, we deal with unsigned integers. :)
ACK

@jonasnick jonasnick force-pushed the fix-ecmult-multi-overflow branch 2 times, most recently from 90ff155 to 24908be Compare October 26, 2018 08:27
@jonasnick
Copy link
Contributor Author

Removed unnecessary else (h/t @dcousens) and squashed

max_points = ECMULT_MAX_POINTS_PER_BATCH;
}
/* Check overflow */
if (n > (size_t)-1 - (max_points-1)) {
Copy link
Contributor

@gmaxwell gmaxwell Oct 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless we have a reason, I think we'd prefer to use stdint SIZE_MAX here. (and in all the other cases where the largest SIZE_T is required)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SIZE_MAX requires C99 as far as I remember.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@real-or-random It is an stdint.h type, like uint32_t. The codebase uses stdint.h ( https://github.com/bitcoin-core/secp256k1/blob/master/src/util.h#L15) types everywhere. In practice every compiler someone would want to use has this header (even non C99 compilers), but if someone did have a compiler without it, they'd have to provide a compatibility header.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I see. It's equivalent but yes, SIZE_MAX is obviously much nicer to read. I was the one who suggested size_t(-1) to @jonasnick in the Schnorr signature PR: #558 (review) Maybe that's why @apoelstra used it in #557 too...

@jonasnick jonasnick force-pushed the fix-ecmult-multi-overflow branch from 24908be to c17ef67 Compare October 30, 2018 16:40
@jonasnick
Copy link
Contributor Author

Replaced (size_t)-1 with MAX_SIZE

@gmaxwell
Copy link
Contributor

ACK

@jimpo
Copy link

jimpo commented Nov 27, 2018

This seems fine, though you could also avoid the overflow checks entirely with

n_batches = 1 + (n-1)/max_points;
n_batch_points = 1 + (n-1)/n_batches;

This should work in all cases since n is guaranteed to be > 0.

@jonasnick jonasnick force-pushed the fix-ecmult-multi-overflow branch from c17ef67 to c37e53d Compare January 15, 2019 19:08
@jonasnick
Copy link
Contributor Author

jonasnick commented Jan 15, 2019

I rewrote this PR with @jimpo's suggestion. I think this is better because the previous code was complex enough that we missed a potential bug [0] and the new code doesn't have unnecessary return 0's. Because n = SIZE_MAX is now actually possible I had to rewrite the tests to directly test the batch_size_helper.

[0] if (n_batches == 0 || n > SIZE_MAX - (*n_batches-1)) { (first asterisk missing)

@real-or-random
Copy link
Contributor

ACK

@jimpo
Copy link

jimpo commented Jan 16, 2019

utACK

@laanwj
Copy link
Member

laanwj commented Feb 21, 2019

utACK c37e53d, changes look correct to me

@gmaxwell
Copy link
Contributor

The addition of the trivial ecmult_multi algorithm in pr580 unfortunately created a trivial merge conflict for this PR, sorry about that. I am ACK on the PR, but need the rebase.

@gmaxwell
Copy link
Contributor

If you'd prefer I can make a fixup commit, whatever you'd be happiest with.

@jonasnick jonasnick force-pushed the fix-ecmult-multi-overflow branch from c37e53d to 2277af5 Compare February 25, 2019 16:13
@gmaxwell gmaxwell merged commit 2277af5 into bitcoin-core:master Feb 25, 2019
gmaxwell added a commit that referenced this pull request Feb 25, 2019
2277af5 Fix integer overflow in ecmult_multi_var when n is large (Jonas Nick)

Pull request description:

  Without this PR ecmult_multi could return wrong results. If the number of points `n` is large enough then some or all multiplications could be skipped or the function could end up in an infinite loop. This PR adds two checks to prevent `n` from wrapping around.

Tree-SHA512: 342944369b24776fa3ec0694eee159259ff67e94d2d8176c1d3159875f387d943d5bfdff7cde59f058e13f07fd09bde1cbc609426e63c8a5b8040e382dd865d8
@gmaxwell
Copy link
Contributor

ACK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants